/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
import { DateObject } from '../types/common';
import { ActiveMonth, MonthViewItem } from '../types/month';
import { UseMonth } from './types';
import { useDate } from './use-date';
import useDisableMonth from './use-disable-month';

export function useMonth(): UseMonth {

    const { getToday } = useDate();
    const { isMonthDisabledByDisableSince, isMonthDisabledByDisableUntil } = useDisableMonth();

    function parseDefaultMonth(monthString: string): ActiveMonth {
        const month: ActiveMonth = { displayTextOfMonth: '', month: 0, year: 0, displayTextOfYear: '' };
        if (monthString) {
            const splitMatchResult = monthString.match(/[^0-9]/);
            const splitKey = (splitMatchResult && splitMatchResult.length) ? splitMatchResult[0] : '';
            const split = monthString.split(splitKey);
            month.month = split[0].length === 2 ? Number(split[0]) : Number(split[1]);
            month.year = split[0].length === 2 ? Number(split[1]) : Number(split[0]);
        }
        return month;
    }

    function daysInMonth(month: number, year: number): number {
        return new Date(year, month, 0).getDate();
    }

    function getDate(year: number, month: number, day: number): Date {
        // Creates a date object from given year, month and day
        return new Date(year, month - 1, day, 0, 0, 0, 0);
    }

    function daysInPreMonth(month: number, year: number): number {
        // Return number of days of the previous month
        const date: Date = getDate(year, month, 1);
        date.setMonth(date.getMonth() - 1);
        return daysInMonth(date.getMonth() + 1, date.getFullYear());
    }

    function generateMonths(
        nameOfMonths: string[],
        selectedMonth: DateObject,
        disableSince: DateObject,
        disableUntil: DateObject
    ): MonthViewItem[][] {
        const today: DateObject = getToday();
        const months: MonthViewItem[][] = [];
        const { year } = selectedMonth;
        const capacityPerRow = 3;

        for (let startMonthInRow = 1; startMonthInRow <= 12; startMonthInRow += capacityPerRow) {
            const monthsInRow: MonthViewItem[] = [];
            for (let month = startMonthInRow; month < startMonthInRow + capacityPerRow; month++) {
                const disable: boolean = isMonthDisabledByDisableSince({ year, month, day: 1 }, disableSince) ||
                    isMonthDisabledByDisableUntil({ year, month, day: daysInMonth(month, year || 0) }, disableUntil);

                monthsInRow.push({
                    month,
                    displayText: nameOfMonths[month],
                    isCurrent: month === today.month && year === today.year,
                    disable,
                    date: { year, month }
                });
            }
            months.push(monthsInRow);
        }
        return months;
    }

    function getNextMonth(month: number, year: number): DateObject {
        const nextMonthDate = {
            year: month === 12 ? year + 1 : year,
        } as DateObject;
        const nextMonth = month === 12 ? 1 : month + 1;
        nextMonthDate.month = nextMonth;
        return nextMonthDate;
    }

    function getPreviousMonth(month: number, year: number): DateObject {
        const previousMonthDate = {
            year: month === 1 ? year - 1 : year
        } as DateObject;
        const previousMonth = month === 1 ? 12 : month - 1;
        previousMonthDate.month = previousMonth;
        return previousMonthDate;
    }

    return { daysInMonth, daysInPreMonth, generateMonths, parseDefaultMonth,getNextMonth,getPreviousMonth };
}
